home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet internetowy / Przegladarki internetowe / Mozilla Seamonkey 1.0.5 pl / seamonkey-1.0.5.pl-PL.win32.installer.exe / MAIL.XPI / bin / chrome / messenger.jar / content / messenger / mailWidgets.xml < prev    next >
Encoding:
Extensible Markup Language  |  2006-01-20  |  75.8 KB  |  1,982 lines

  1. <?xml version="1.0"?>
  2.  
  3. <bindings   id="mailBindings"
  4.             xmlns="http://www.mozilla.org/xbl"
  5.             xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
  6.             xmlns:nc="http://home.netscape.com/NC-rdf#"
  7.             xmlns:xbl="http://www.mozilla.org/xbl">
  8.  
  9.   <!-- dummy widget to force this file to load -->
  10.   <binding id="dummy" extends="xul:box"/>
  11.  
  12.   <!-- temporary holding place for horizontal list -->
  13.  
  14.   <binding id="extdescription" extends="chrome://global/content/bindings/text.xml#text-base">
  15.     <implementation implements="nsIDOMXULMultiSelectControlElement, nsIDOMXULSelectControlElement">
  16.       <field name="_isUpSelection">0</field>
  17.       <field name="_isDownSelection">0</field>
  18.       <field name="_suppressOnSelect">false</field>
  19.       <field name="_selectionStart">null</field>
  20.       <field name="_currentItem">null</field>
  21.       <field name="_selectTimeout">null</field>
  22.       <field name="_lastKeyTime">0</field>
  23.       <field name="_incrementalString">""</field>
  24.  
  25.       <constructor>
  26.         <![CDATA[
  27.           var els = this.getElementsByAttribute("selected", "true");
  28.           this.selectedItems = [];
  29.           for (var i = 0; i < els.length; ++i)
  30.             this.selectedItems.push(els[i]);
  31.         ]]>
  32.       </constructor>
  33.            
  34.       <!-- ///////////////// public members ///////////////// -->
  35.       <property name="_selectDelay" 
  36.                 onset="this.setAttribute('_selectDelay', val);"
  37.                 onget="return this.getAttribute('_selectDelay') || 50;"/>
  38.       
  39.       <method name="timedSelect">
  40.         <parameter name="item"/>
  41.         <parameter name="timeout"/>
  42.         <body>
  43.         <![CDATA[
  44.           var suppress = this._suppressOnSelect;
  45.           if (timeout != -1)
  46.             this._suppressOnSelect = true;
  47.           
  48.           this.selectItem(item);
  49.           
  50.           this._suppressOnSelect = suppress;         
  51.           
  52.           if (timeout != -1) {
  53.             if (this._selectTimeout)
  54.               window.clearTimeout(this._selectTimeout);
  55.               
  56.             this._selectTimeout = window.setTimeout(this._selectTimeoutHandler, timeout, this); 
  57.           }
  58.         ]]>
  59.         </body>
  60.       </method>  
  61.  
  62.       <method name="appendItem">
  63.         <parameter name="label"/>
  64.         <body>
  65.         <![CDATA[
  66.           var XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
  67.           var item = document.createElementNS(XULNS, "descriptionitem");
  68.           item.setAttribute("label", label);
  69.           this.appendChild(item);
  70.           return item;
  71.         ]]>
  72.         </body>
  73.       </method>
  74.       
  75.       <!-- ///////////////// private members ///////////////// -->
  76.  
  77.       <method name="_fireOnSelect">
  78.         <body>
  79.         <![CDATA[
  80.           if (!this._suppressOnSelect && this.getAttribute("suppressonselect") != "true") {
  81.             var event = document.createEvent("Events");
  82.             event.initEvent("select", false, true);
  83.             this.dispatchEvent(event);
  84.           }
  85.         ]]>
  86.         </body>
  87.       </method>
  88.  
  89.       <method name="_selectTimeoutHandler">
  90.         <parameter name="me"/>
  91.         <body>
  92.         <![CDATA[
  93.           me._fireOnSelect();
  94.           me._selectTimeout = null;
  95.         ]]>
  96.         </body>
  97.       </method>
  98.  
  99.       <!-- ///////////////// nsIDOMXULSelectControlElement ///////////////// -->
  100.  
  101.       <property name="selType"
  102.                 onget="return this.getAttribute('seltype')"
  103.                 onset="this.setAttribute('seltype', val); return val;"/>
  104.  
  105.       <property name="selectedIndex">
  106.         <getter><![CDATA[
  107.           return this.selectedItems.length > 0 ? this.getIndexOfItem(this.selectedItems[0]) : -1;
  108.         ]]></getter>
  109.         <setter><![CDATA[
  110.           if (val >= 0)
  111.             this.selectItem(this.getItemAtIndex(val));
  112.           else
  113.             this.clearSelection();
  114.         ]]></setter>
  115.       </property>
  116.  
  117.       <property name="selectedItem">
  118.         <getter><![CDATA[
  119.           return this.selectedItems.length > 0 ? this.selectedItems[0] : null;
  120.         ]]></getter>
  121.         <setter><![CDATA[
  122.           this.selectItem(val);
  123.         ]]></setter>
  124.       </property>
  125.  
  126.       <!-- ///////////////// nsIDOMXULSelectMultipleControlElement ///////////////// -->
  127.  
  128.       <property name="currentItem" onget="return this._currentItem;">
  129.         <setter>
  130.         <![CDATA[
  131.           if (this._currentItem)
  132.             this._currentItem.removeAttribute("current");
  133.           this._currentItem = val;
  134.           if (val)
  135.             val.setAttribute("current", "true");          
  136.           return val;
  137.         ]]>
  138.         </setter>
  139.       </property>
  140.       
  141.       <property name="selectedCount" onget="return this.selectedItems.length;"/>
  142.       
  143.       <method name="getSelectedItem">
  144.         <parameter name="index"/>
  145.         <body>
  146.         <![CDATA[
  147.           return index < this.selectedItems.length ? this.selectedItems[index] : null;
  148.         ]]>
  149.         </body>
  150.       </method>      
  151.       
  152.       <method name="addItemToSelection">
  153.         <parameter name="item"/>
  154.         <body>
  155.         <![CDATA[
  156.           if (this.selType != "multiple" && this.selectedCount)
  157.             return;
  158.           if (item.hasAttribute("selected"))
  159.             return;            
  160.           this.selectedItems.push(item);
  161.           item.setAttribute("selected", "true");       
  162.           this._fireOnSelect();
  163.         ]]>
  164.         </body>
  165.       </method>      
  166.       
  167.       <method name="removeItemFromSelection">
  168.         <parameter name="item"/>
  169.         <body>
  170.         <![CDATA[
  171.           if (!item.hasAttribute("selected"))
  172.             return;
  173.             
  174.           for (var i = 0; i < this.selectedItems.length; ++i) {
  175.             if (this.selectedItems[i] == item) {
  176.               this.selectedItems.splice(i, 1);
  177.               item.removeAttribute("selected"); 
  178.               break;
  179.             }
  180.           }
  181.               
  182.           this._fireOnSelect();
  183.         ]]>
  184.         </body>
  185.       </method>      
  186.       
  187.       <method name="toggleItemSelection">
  188.         <parameter name="item"/>
  189.         <body>
  190.         <![CDATA[
  191.           if (item.hasAttribute("selected"))
  192.             this.removeItemFromSelection(item);
  193.           else
  194.             this.addItemToSelection(item);
  195.         ]]>
  196.         </body>
  197.       </method>      
  198.       
  199.       <method name="selectItem">
  200.         <parameter name="item"/>
  201.         <body>
  202.         <![CDATA[
  203.           if (!item)
  204.             return;
  205.             
  206.           if (this.selectedItems.length == 1 && this.selectedItems[0] == item)
  207.             return;
  208.           
  209.           this._selectionStart = null;
  210.           
  211.           var suppress = this._suppressOnSelect;
  212.           this._suppressOnSelect = true;
  213.  
  214.           this.clearSelection();
  215.           this.addItemToSelection(item);
  216.           this.currentItem = item;
  217.           
  218.           this._suppressOnSelect = suppress;
  219.           this._fireOnSelect();
  220.         ]]>
  221.         </body>
  222.       </method>      
  223.       
  224.       <method name="selectItemRange">
  225.         <parameter name="startItem"/>
  226.         <parameter name="endItem"/>
  227.         <body>
  228.         <![CDATA[
  229.           if (this.selType != "multiple")
  230.             return;
  231.  
  232.           if (!startItem)
  233.             startItem = this._selectionStart ? this._selectionStart : this.currentItem;
  234.           if (!startItem)
  235.             startItem = endItem;
  236.                       
  237.           var suppressSelect = this._suppressOnSelect;
  238.           this._suppressOnSelect = true;
  239.           this.clearSelection();
  240.  
  241.           this._selectionStart = startItem;
  242.           
  243.           var currentItem;
  244.           var startIndex = this.getIndexOfItem(startItem);
  245.           var endIndex = this.getIndexOfItem(endItem);
  246.           if (endIndex < startIndex) {
  247.             currentItem = endItem;
  248.             endItem = startItem;
  249.             startItem = currentItem;            
  250.           } else {
  251.             currentItem = startItem;
  252.           }
  253.             
  254.           while (currentItem) {
  255.             if (currentItem.localName == "descriptionitem")
  256.               this.addItemToSelection(currentItem);
  257.             if (currentItem == endItem)
  258.               break;
  259.             currentItem = this.getNextItem(currentItem, 1);
  260.           }
  261.  
  262.           this._suppressOnSelect = suppressSelect;
  263.           
  264.           this._fireOnSelect();
  265.         ]]>
  266.         </body>
  267.       </method>      
  268.       
  269.       <method name="selectAll">
  270.         <body>
  271.         <![CDATA[
  272.           var suppress = this._suppressOnSelect;
  273.           this._suppressOnSelect = true;
  274.           
  275.           var item = this.getItemAtIndex(0);
  276.           while (item) {
  277.             this.addItemToSelection(item);
  278.             item = this.getNextItem(item, 1);  
  279.           }
  280.           
  281.           this._suppressOnSelect = suppress;
  282.           this._fireOnSelect();
  283.         ]]>
  284.         </body>
  285.       </method>      
  286.       
  287.       <method name="invertSelection">
  288.         <body>
  289.         <![CDATA[
  290.           var suppress = this._suppressOnSelect;
  291.           this._suppressOnSelect = true;
  292.           
  293.           var item = this.getItemAtIndex(0);
  294.           while (item) {
  295.             if (item.hasAttribute("selected"))
  296.               this.removeItemFromSelection(item);
  297.             else
  298.               this.addItemToSelection(item);
  299.             item = this.getNextItem(item, 1);  
  300.           }
  301.           
  302.           this._suppressOnSelect = suppress;
  303.           this._fireOnSelect();
  304.         ]]>
  305.         </body>
  306.       </method>      
  307.       
  308.       <method name="clearSelection">
  309.         <body>
  310.         <![CDATA[
  311.           if (this.selectedItems)
  312.           {
  313.             for (var i = this.selectedItems.length-1; i >= 0; --i)
  314.               this.selectedItems[i].removeAttribute("selected");
  315.           
  316.             this.selectedItems.splice(0, this.selectedItems.length);
  317.           }
  318.           this._selectionStart = null;
  319.           this._fireOnSelect();
  320.         ]]>
  321.         </body>
  322.       </method>
  323.  
  324.       <method name="getNextItem">
  325.         <parameter name="startItem"/>
  326.         <parameter name="delta"/>
  327.         <body><![CDATA[
  328.           while (startItem) {
  329.             startItem = startItem.nextSibling;
  330.             if (startItem && startItem.localName == "descriptionitem") {
  331.               --delta;
  332.               if (delta == 0)
  333.                 return startItem;
  334.             }
  335.           }
  336.           return null;
  337.         ]]></body>
  338.       </method>
  339.       
  340.       <method name="getPreviousItem">
  341.         <parameter name="startItem"/>
  342.         <parameter name="delta"/>
  343.         <body><![CDATA[
  344.           while (startItem) {
  345.             startItem = startItem.previousSibling;
  346.             if (startItem && startItem.localName == "descriptionitem") {
  347.               --delta;
  348.               if (delta == 0)
  349.                 return startItem;
  350.             }
  351.           }
  352.           return null;
  353.         ]]></body>
  354.       </method>
  355.  
  356.       <!-- selection navigation --> 
  357.       <method name="navigateToPreviousItem">
  358.         <parameter name="event"/>
  359.         <body>
  360.         <![CDATA[  
  361.            if (event.target != this)
  362.              return;                
  363.           this._isUpSelection=0;
  364.           this._isDownSelection=0;
  365.           var n = this.getPreviousItem(this.selectedItems[this.selectedItems.length-1], 1);
  366.           if (n)
  367.             this.timedSelect(n, this._selectDelay);
  368.           ]]>
  369.         </body>
  370.       </method>
  371.  
  372.       <method name="navigateToNextItem">
  373.         <parameter name="event"/>
  374.         <body>
  375.           <![CDATA[  
  376.            if (event.target != this)
  377.              return;                
  378.            var n;
  379.            if (this.selectedItems.length == 0) {
  380.              n = this.getItemAtIndex(0);
  381.            }
  382.            else 
  383.            {
  384.              this._isUpSelection=0;
  385.              this._isDownSelection=0;
  386.              n = this.getNextItem(this.selectedItems[this.selectedItems.length-1], 1);
  387.            }
  388.  
  389.            if (n) 
  390.              this.timedSelect(n, this._selectDelay);
  391.           ]]>
  392.         </body>
  393.       </method>
  394.       
  395.       <method name="navigateAndSelectNextItem">
  396.         <parameter name="event"/>
  397.         <body>
  398.           <![CDATA[ 
  399.             var l=this.selectedItems.length;
  400.             if (event.target != this || l < 1 || this.selType != "multiple")
  401.               return;
  402.             var n = this.getNextItem(this.selectedItems[l-1], 1);
  403.             if (n) 
  404.             {
  405.               if ( this._isUpSelection) 
  406.               {
  407.                 if ( l > 1 )
  408.                   this.removeItemFromSelection(this.selectedItems[l-1]);
  409.                 if ( l <= 2 )
  410.                   this._isUpSelection=0;
  411.               }
  412.               else 
  413.               {
  414.                 this.addItemToSelection(n);
  415.                 this._isDownSelection=1;
  416.               }
  417.             }
  418.           ]]>
  419.         </body>
  420.       </method>
  421.       <method name="navigateAndSelectPreviousItem">
  422.         <parameter name="event"/>
  423.         <body>
  424.           <![CDATA[ 
  425.             var l = this.selectedItems.length;
  426.             if (event.target != this || l < 1 || this.selType != "multiple")
  427.               return;
  428.             var n = this.getPreviousItem(this.selectedItems[l-1], 1);
  429.             if (n) 
  430.             {
  431.               if ( this._isDownSelection) 
  432.               {
  433.                 if ( l > 1 )
  434.                   this.removeItemFromSelection(this.selectedItems[l-1]);
  435.                 if ( l <= 2 )
  436.                   this._isDownSelection=0;
  437.               } else 
  438.               {
  439.                 this.addItemToSelection(n);
  440.                 this._isUpSelection=1;
  441.               }
  442.             }          
  443.           ]]>
  444.         </body>
  445.       </method>
  446.     </implementation>
  447.  
  448.     <handlers>     
  449.       
  450.       <handler event="keypress" modifiers="shift" keycode="vk_down">
  451.         <![CDATA[
  452.           this.navigateAndSelectNextItem(event);
  453.         ]]>
  454.       </handler>
  455.  
  456.       <handler event="keypress" modifiers="shift" keycode="vk_right">
  457.         <![CDATA[
  458.           this.navigateAndSelectNextItem(event);
  459.         ]]>
  460.       </handler>
  461.       <handler event="keypress" modifiers="shift" keycode="vk_up">
  462.         <![CDATA[
  463.           this.navigateAndSelectPreviousItem(event);
  464.         ]]>
  465.       </handler>
  466.  
  467.       <handler event="keypress" modifiers="shift" keycode="vk_left">
  468.         <![CDATA[
  469.           this.navigateAndSelectPreviousItem(event);
  470.         ]]>
  471.       </handler>
  472.            
  473.       <handler event="keypress" keycode="vk_up">
  474.         <![CDATA[
  475.           this.navigateToPreviousItem(event);
  476.         ]]>
  477.       </handler>
  478.       <handler event="keypress" keycode="vk_left">
  479.         <![CDATA[
  480.           if (event.target != this)
  481.             return;
  482.           this.navigateToPreviousItem(event);
  483.         ]]>
  484.       </handler>
  485.       <handler event="keypress" keycode="vk_down">
  486.         <![CDATA[
  487.           this.navigateToNextItem(event);
  488.         ]]>
  489.       </handler>
  490.       <handler event="keypress" keycode="vk_right">
  491.         <![CDATA[
  492.           this.navigateToNextItem(event);
  493.         ]]>
  494.       </handler>
  495.       <handler event="mousedown">
  496.       <![CDATA[
  497.         var targetItem = event.target;
  498.         if (targetItem.localName == "descriptionitem" && !event.ctrlKey && !event.shiftKey && !event.metaKey) 
  499.         {
  500.           if (!targetItem.hasAttribute('selected')) 
  501.             this.selectItem(targetItem);
  502.           this.currentItem = targetItem;
  503.         }
  504.         if (document.commandDispatcher.focusedElement != this) 
  505.           this.focus(); // make sure the description has focus...
  506.       ]]>
  507.       </handler>
  508.       <handler event="click">
  509.       <![CDATA[
  510.         if (event.button != 0) return;
  511.  
  512.         var targetItem = event.target;
  513.         if (targetItem.localName == "descriptionitem") 
  514.         {
  515.           if (this.selType != "multiple")
  516.             this.selectItem(targetItem);
  517.           else if (event.ctrlKey || event.metaKey) {
  518.             this.toggleItemSelection(targetItem);
  519.             this.currentItem = targetItem;
  520.           }
  521.           else if (event.shiftKey) {
  522.             this.selectItemRange(null, targetItem);
  523.             this.currentItem = targetItem;
  524.           }
  525.           else {
  526.             /* We want to deselect all the selected items except what was
  527.                clicked, UNLESS it was a right-click.  We have to do this
  528.                in click rather than mousedown so that you can drag a
  529.                selected group of items */
  530.             
  531.             var selectedItems = this.selectedItems;
  532.             var didSuppressSelect = false;
  533.             var i = 0;
  534.             while (i < selectedItems.length) 
  535.             {
  536.               if (selectedItems[i] != targetItem) 
  537.               {
  538.                 if (!didSuppressSelect) 
  539.                 {
  540.                   this._suppressOnSelect = true;
  541.                   didSuppressSelect = true;
  542.                 }
  543.                 this.removeItemFromSelection(selectedItems[i]);
  544.               }
  545.               else
  546.                 i++;
  547.             }
  548.             if (didSuppressSelect)
  549.               this._suppressOnSelect = false;
  550.           }
  551.         }
  552.         else 
  553.         {
  554.           if (this.selType != "multiple" || (!event.ctrlKey && !event.shiftKey && !event.metaKey))
  555.             this.clearSelection();
  556.         }
  557.       ]]>
  558.       </handler>
  559.     </handlers>
  560.   </binding>
  561.  
  562.   <binding id="descriptionitem">
  563.     <content>
  564.       <xul:hbox class="attachmentBox" xbl:inherits="orient" align="start">
  565.         <xul:label class="descriptioncell-label" xbl:inherits="value=label,flex=flexlabel,crop,disabled,context" flex="1" dir="ltr" crop="center"/>
  566.       </xul:hbox>
  567.     </content>
  568.   </binding>
  569.  
  570.   <binding id="descriptionitem-iconic">
  571.     <content>
  572.       <xul:hbox class="attachmentBox" xbl:inherits="orient" align="center">
  573.         <xul:image class="descriptioncell-icon" xbl:inherits="src=image"/>
  574.         <xul:label class="descriptioncell-label" xbl:inherits="value=label,flex=flexlabel,crop,disabled,context" flex="1" dir="ltr" crop="center"/>
  575.       </xul:hbox>
  576.     </content>
  577.   </binding>
  578.  
  579.   <!-- Message Pane Widgets -->
  580.  
  581.   <!-- mail-toggle-headerfield: non email addrss headers which have a toggle associated with them (i.e. the subject). 
  582.        use label to set the header name.
  583.        use headerValue to set the header value. -->
  584.   <binding id="mail-toggle-headerfield">
  585.     <content>
  586.       <xul:hbox class="headerNameBox" align="start">
  587.         <xul:image class="expandHeaderViewButton" xbl:inherits="onclick=ontwistyclick"/>
  588.         <xul:spacer flex="1"/>
  589.         <xul:label class="headerName" xbl:inherits="value=label"/>  
  590.       </xul:hbox>
  591.       <xul:textbox originalclass="headerValue plain" appendoriginalclass="true" keywordrelated="true" class="headerValue plain" anonid="headerValue" flex="1" readonly="true"/>
  592.     </content>
  593.  
  594.     <implementation>      
  595.       <property name="headerValue" onset="return document.getAnonymousElementByAttribute(this, 'anonid', 'headerValue').value = val;"/>
  596.     </implementation>
  597.   </binding>
  598.  
  599.   <!-- mail-headerfield: presents standard text header name & value pairs. Don't use this for email addresses. 
  600.        use label to set the header name.
  601.        use headerValue to set the header value. -->
  602.   <binding id="mail-headerfield">
  603.     <content>
  604.       <xul:hbox class="headerNameBox" align="start">
  605.         <xul:label class="headerName" xbl:inherits="value=label" flex="1"/>
  606.       </xul:hbox>
  607.       <xul:textbox originalclass="headerValue plain" appendoriginalclass="true" keywordrelated="true" class="headerValue plain" anonid="headerValue" flex="1" readonly="true"/> 
  608.     </content>
  609.  
  610.     <implementation>      
  611.       <property name="headerValue" onset="return document.getAnonymousElementByAttribute(this, 'anonid', 'headerValue').value = val;"/>  
  612.     </implementation>
  613.   </binding>
  614.  
  615.   <binding id="mail-urlfield" extends="chrome://messenger/content/mailWidgets.xml#mail-headerfield">
  616.     <content>
  617.       <xul:hbox class="headerNameBox" align="start">
  618.         <xul:label class="headerName" xbl:inherits="value=label" flex="1"/>
  619.       </xul:hbox>
  620.       <xul:label originalclass="headerValue plain headerValueUrl" onclick="if (!event.button) messenger.launchExternalURL(event.target.value);" 
  621.                  appendoriginalclass="true" keywordrelated="true" class="headerValue plain headerValueUrl" 
  622.                  anonid="headerValue" flex="1" readonly="true" context="copyUrlPopup"/> 
  623.     </content>
  624.   </binding>
  625.  
  626.   <binding id="mail-emailheaderfield">
  627.     <content>
  628.       <xul:hbox class="headerNameBox" align="start">
  629.         <xul:label class="headerName" xbl:inherits="value=label" flex="1"/>
  630.       </xul:hbox>
  631.       <xul:mail-emailaddress anonid="emailAddressNode"/>
  632.     </content>
  633.  
  634.     <implementation>
  635.       <property name="emailAddressNode" onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'emailAddressNode');"
  636.         readonly="true"/>
  637.     </implementation>
  638.   </binding>
  639.   
  640.   <!-- multi-emailHeaderField: presents multiple emailheaderfields with a toggle -->
  641.   <binding id="mail-multi-emailHeaderField">
  642.     <content>
  643.       <xul:hbox class="headerNameBox" align="start" pack="end">
  644.         <xul:image class="addresstwisty" anonid="toggleIcon"
  645.                    onclick="toggleAddressView();"/>
  646.         <xul:label class="headerName" xbl:inherits="value=label"/>
  647.         </xul:hbox>
  648.  
  649.         <xul:label class="headerValue" anonid="emailAddresses" flex="1"/>
  650.         <xul:label class="headerValue" anonid="longEmailAddresses" flex="1" collapsed="true"/>
  651.     </content>
  652.  
  653.     <implementation>
  654.       <constructor>
  655.         <![CDATA[
  656.           this.mLongViewCreated = false;
  657.           this.mAddresses = new Array;
  658.         ]]>
  659.       </constructor>
  660.  
  661.       <field name="mLongViewCreated"/>
  662.       <field name="mAddresses"/>
  663.       <!-- as a perf optimization we are going to keep a cache of email address nodes which we've
  664.            created around for the lifetime of the widget. mSizeOfAddressCache controls how many of these
  665.            elements we keep around -->
  666.       <field name="mSizeOfAddressCache">3</field>
  667.       
  668.       <!-- addAddressView: a public method used to add an address to this widget. 
  669.            aAddresses is an object with 3 properties: displayName, emailAddress and fullAddress
  670.       -->
  671.       <method name="addAddressView">
  672.         <parameter name="aAddress"/>
  673.         <body>
  674.           <![CDATA[
  675.             this.mAddresses.push(aAddress);
  676.           ]]>
  677.         </body>
  678.       </method>
  679.       
  680.       <!-- updateEmailAddressNode: private method used to set properties on an address node -->
  681.       <method name="updateEmailAddressNode">
  682.         <parameter name="aEmailNode"/>
  683.         <parameter name="aAddress"/>
  684.         <body>
  685.           <![CDATA[
  686.             aEmailNode.setAttribute("label", aAddress.fullAddress);    
  687.             aEmailNode.setTextAttribute("emailAddress", aAddress.emailAddress);
  688.             aEmailNode.setTextAttribute("fullAddress", aAddress.fullAddress);  
  689.             aEmailNode.setTextAttribute("displayName", aAddress.displayName);
  690.  
  691.             try
  692.             {
  693.               if ("AddExtraAddressProcessing" in top)
  694.                 AddExtraAddressProcessing(aAddress.emailAddress, aEmailNode);
  695.             }
  696.             catch(ex)
  697.             {
  698.               dump("AddExtraAddressProcessing failed: " + ex);
  699.             }
  700.           ]]>
  701.         </body>
  702.       </method>
  703.  
  704.       <!-- fillCachedAddresses: private method used to fill up any cached pre-existing
  705.            emailAddress fields without creating new email address fields. Returns a remainder
  706.            for the # of addresses which require new addresses being created.
  707.            Invariants: 1) aNumAddressesToShow >= 0 && it is <= mAddresses.length -->
  708.       <method name="fillCachedAddresses">
  709.         <parameter name="aAddressesNode"/>
  710.         <parameter name="aNumAddressesToShow"/>
  711.         <body>
  712.           <![CDATA[
  713.             var numExistingCachedAddresses = aAddressesNode.childNodes.length;
  714.             if (!numExistingCachedAddresses) 
  715.               return this.mAddresses.length; // we couldn't pre fill anything
  716.             else if (numExistingCachedAddresses > 1)
  717.               numExistingCachedAddresses = (numExistingCachedAddresses + 1)/ 2;
  718.             
  719.             var index = 0; 
  720.             var numAddressesAdded = 0;
  721.             var emailAddressNode;
  722.             var commaNode;
  723.             while (numAddressesAdded < numExistingCachedAddresses && numAddressesAdded < aNumAddressesToShow)
  724.             {
  725.               if (index && numExistingCachedAddresses > 1)
  726.               {
  727.                 commaNode = aAddressesNode.childNodes[index++];
  728.                 if (commaNode)
  729.                   commaNode.removeAttribute('collapsed');
  730.               }
  731.  
  732.               // get the node pointed to by index
  733.               emailAddressNode = aAddressesNode.childNodes[index++];
  734.               this.updateEmailAddressNode(emailAddressNode, this.mAddresses[numAddressesAdded]);
  735.               emailAddressNode.removeAttribute('collapsed');
  736.               numAddressesAdded++;
  737.             }
  738.  
  739.             // if we have added all of our elements but we still have more cached items in this address node
  740.             // then make sure the extra cached copies are collapsed...
  741.             numExistingCachedAddresses = aAddressesNode.childNodes.length;  // reset
  742.             while (index < numExistingCachedAddresses)
  743.             {
  744.               aAddressesNode.childNodes[index++].setAttribute('collapsed', true);
  745.             }
  746.  
  747.             return this.mAddresses.length - numAddressesAdded;
  748.           ]]>
  749.         </body>
  750.       </method>
  751.  
  752.       <!-- fillAddressesNode: private method used to create email address nodes for either our short
  753.            or long view. aAddressesNode: the div we want to add addresses too. 
  754.           aNumAddressesToShow: number of addresses to put into the list -->
  755.       <method name="fillAddressesNode">
  756.         <parameter name="aAddressesNode"/>
  757.         <parameter name="aNumAddressesToShow"/>
  758.         <body>
  759.           <![CDATA[
  760.             var numAddresses = this.mAddresses.length;
  761.             if (aNumAddressesToShow <= 0 || aNumAddressesToShow > numAddresses)  // then show all
  762.               aNumAddressesToShow = numAddresses;
  763.  
  764.             // before we try to create email address nodes, try to leverage any cached nodes...
  765.             var remainder = this.fillCachedAddresses(aAddressesNode, aNumAddressesToShow);
  766.             var index = numAddresses - remainder; 
  767.             while (index < numAddresses && index < aNumAddressesToShow)
  768.             {
  769.               var newAddressNode = document.createElement("mail-emailaddress");
  770.               if (index)
  771.               {
  772.                 var textNode = document.createElement("text");
  773.                 textNode.setAttribute("value", ", ");
  774.                 textNode.setAttribute("class", "emailSeparator");
  775.                 aAddressesNode.appendChild(textNode);
  776.               }              
  777.               
  778.               var itemInDocument = aAddressesNode.appendChild(newAddressNode);
  779.               this.updateEmailAddressNode(itemInDocument, this.mAddresses[index]);
  780.               index++;
  781.             }
  782.           ]]>
  783.         </body>
  784.       </method>
  785.  
  786.       <property name="emailAddresses" onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'emailAddresses');"
  787.         readonly="true"/>
  788.       <property name="longEmailAddresses" onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'longEmailAddresses');"
  789.         readonly="true"/> 
  790.       <property name="toggleIcon" onget="return document.getAnonymousElementByAttribute(this, 'anonid', 'toggleIcon');"
  791.         readonly="true"/>
  792.  
  793.       <!-- buildView: public method used by callers when they are done adding all the email addresses to the widget
  794.            aNumAddressesToShow: total # of addresses to show in the short view -->
  795.       <method name="buildViews">
  796.         <parameter name="aNumAddressesToShow"/>
  797.         <body>
  798.           <![CDATA[
  799.             // always build the short view...its cheap...
  800.             this.fillAddressesNode(this.emailAddresses, aNumAddressesToShow);
  801.             // if we are currently toggled to show all the email addresses, build the long one too...
  802.             if (this.emailAddresses.collapsed)
  803.               this.buildLongView();
  804.  
  805.             // make sure the icon is always visible if we have more than the # of addresses to show     
  806.             this.toggleIcon.collapsed = this.mAddresses.length <= aNumAddressesToShow;
  807.           ]]> 
  808.         </body>
  809.       </method>
  810.             
  811.       <!-- buildLongView: private method used for delayed construction of the long view -->
  812.       <method name="buildLongView">
  813.         <body>
  814.           <![CDATA[
  815.             if (!this.mLongViewCreated)
  816.             {
  817.               this.fillAddressesNode(this.longEmailAddresses, -1);
  818.               this.mLongViewCreated = true;
  819.             }
  820.           ]]> 
  821.         </body>
  822.       </method>
  823.  
  824.       <method name="toggleAddressView">
  825.         <body>
  826.           <![CDATA[
  827.           var shortNode = this.emailAddresses;
  828.           var longNode = this.longEmailAddresses;
  829.           var imageNode = this.toggleIcon;
  830.           // test to see which if short is already collapsed...
  831.           if (shortNode.collapsed)
  832.           {
  833.             longNode.collapsed = true;
  834.             shortNode.collapsed = false;
  835.             imageNode.removeAttribute("open");
  836.           }
  837.           else
  838.           {
  839.             this.buildLongView();
  840.             shortNode.collapsed = true;
  841.             longNode.collapsed = false;
  842.             imageNode.setAttribute("open", "true");
  843.  
  844.             if (!this.mLongViewCreated)
  845.             {
  846.               // Need to call UpdateMessageHeaders() because this is the first
  847.               // time the long view is being built.  This is required in order
  848.               // to update the addresses of the long view that might contain
  849.               // extra image info.
  850.               // It should also only be called from toggleAddressView(), not
  851.               // from buildView().
  852.               UpdateMessageHeaders();
  853.             }
  854.           }
  855.           ]]>  
  856.         </body>
  857.       </method>
  858.       
  859.       <!-- internal method used to clear both our divs -->
  860.       <method name="clearChildNodes">
  861.         <parameter name="aParentNode"/>
  862.         <body>
  863.           <![CDATA[
  864.             // we want to keep around the first mSizeOfAddressCache email address nodes
  865.             // don't forget that we have comma text nodes in there too so really we want to keep
  866.             // around cache size * 2 - 1.
  867.             var numItemsToPreserve = this.mSizeOfAddressCache * 2 - 1;
  868.             var numItemsInNode = aParentNode.childNodes.length;
  869.  
  870.             while (numItemsInNode && (numItemsInNode > numItemsToPreserve))
  871.             { 
  872.               aParentNode.removeChild(aParentNode.childNodes[numItemsInNode-1]);
  873.               numItemsInNode = numItemsInNode - 1;
  874.             }
  875.           ]]>       
  876.         </body>
  877.       </method>
  878.  
  879.       <method name="clearEmailAddresses">
  880.         <body>
  881.           <![CDATA[
  882.             // clear out our local state
  883.             this.mAddresses = new Array; 
  884.             this.mLongViewCreated = false;
  885.  
  886.             // remove anything inside of each of our labels....
  887.             var parentLabel = this.emailAddresses;
  888.             if (parentLabel)
  889.               this.clearChildNodes(parentLabel);
  890.             parentLabel = this.longEmailAddresses;
  891.             if (parentLabel)
  892.               this.clearChildNodes(parentLabel);             
  893.           ]]>
  894.         </body>
  895.       </method>       
  896.     </implementation>
  897.   </binding>
  898.  
  899.   <binding id="mail-emailaddress">
  900.     <content popup="emailAddressPopup" context="emailAddressPopup">
  901.       <xul:label anonid="emailValue" class="emailDisplayButton plain"                 
  902.                  xbl:inherits="value=label,crop"/>
  903.       <xul:image class="emailDisplayImage" anonid="emailImage"
  904.                  xbl:inherits="src=image"/>
  905.     </content>
  906.     
  907.     <implementation>  
  908.       <property name="label"      onset="this.getPart('emailValue').setAttribute('label',val); return val;"
  909.                                   onget="return this.getPart('emailValue').getAttribute('label');"/>
  910.       <property name="crop"       onset="this.getPart('emailValue').setAttribute('crop',val); return val;"
  911.                                   onget="return this.getPart('emailValue').getAttribute('crop');"/>
  912.       <property name="disabled"   onset="this.getPart('emailValue').setAttribute('disabled',val); return val;"
  913.                                   onget="return this.getPart('emailValue').getAttribute('disabled');"/>
  914.       <property name="src"        onset="this.getPart('emailImage').setAttribute('src',val); return val;"
  915.                                   onget="return this.getPart('emailImage').getAttribute('src');"/>
  916.       <property name="imgalign"   onset="this.getPart('emailImage').setAttribute('imgalign',val); return val;"
  917.                                   onget="return this.getPart('emailImage').getAttribute('imgalign');"/>
  918.  
  919.       <method name="getPart">
  920.         <parameter name="aPartId"/>
  921.         <body><![CDATA[
  922.           return document.getAnonymousElementByAttribute(this, "anonid", aPartId);
  923.         ]]></body>
  924.       </method>
  925.  
  926.       <method name="setTextAttribute">
  927.         <parameter name="attributeName"/>
  928.         <parameter name="attributeValue"/>
  929.         <body><![CDATA[
  930.           this.setAttribute(attributeName, attributeValue);
  931.           this.getPart("emailImage").setAttribute(attributeName, attributeValue);          
  932.           this.getPart("emailValue").setAttribute(attributeName, attributeValue);          
  933.         ]]></body>
  934.       </method>
  935.  
  936.       <method name="getTextAttribute">
  937.         <parameter name="attributeName"/>
  938.         <body><![CDATA[   
  939.           return this.getPart("emailValue").getAttribute(attributeName);
  940.         ]]></body>
  941.       </method>
  942.  
  943.       <method name="GetIconNode">
  944.         <body><![CDATA[
  945.           return this.getPart("emailImage");
  946.         ]]></body>
  947.       </method>
  948.     </implementation>
  949.   </binding>
  950.  
  951.   <binding id="search-menulist-abstract" name="searchMenulistAbstract" extends="xul:box">
  952.     <content>
  953.       <xul:menulist class="search-menulist" xbl:inherits="flex" oncommand="this.parentNode.onSelect(event)">
  954.         <xul:menupopup class="search-menulist-popup"/>
  955.       </xul:menulist>
  956.     </content>
  957.  
  958.     <implementation>
  959.       <field name="internalScope">null</field>
  960.       <field readonly="true" name="validityManager">
  961.         <![CDATA[
  962.            Components.classes['@mozilla.org/mail/search/validityManager;1'].getService(Components.interfaces.nsIMsgSearchValidityManager);
  963.         ]]>
  964.       </field>
  965.       <property name="searchScope" onget="return this.internalScope;">
  966.         <!-- scope ID - retrieve the table -->
  967.         <setter>
  968.           <![CDATA[
  969.             // if scope isn't changing this is a noop
  970.             if (this.internalScope == val) return val;
  971.  
  972.             this.internalScope = val;
  973.             this.refreshList();
  974.             var targets = this.targets;
  975.             if (targets) {
  976.               for (var i=0; i< targets.length; i++) {
  977.                 targets[i].searchScope = val;
  978.               }
  979.             }
  980.             return val;
  981.           ]]>
  982.         </setter>
  983.       </property>
  984.  
  985.       <property name="validityTable" readonly="true" onget="return this.validityManager.getTable(this.searchScope)"/>
  986.  
  987.       <property name="valueStrings" readonly="true">
  988.         <getter>
  989.           <![CDATA[
  990.             var strings = new Array;
  991.             var ids = this.valueIds;
  992.             var pref = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
  993.             var hdrsArray = null;
  994.             try
  995.             {
  996.               var hdrs = pref.getCharPref("mailnews.customHeaders");
  997.               hdrs = hdrs.replace(/\s+/g,'');  //remove white spaces before splitting 
  998.               hdrsArray = hdrs.match(/[^:]+/g);
  999.             }
  1000.             catch(ex)
  1001.             {
  1002.             }
  1003.             var bundle = this.stringBundle;
  1004.             var j=0;
  1005.             for (var i=0; i<ids.length; i++)
  1006.             {
  1007.               if(ids[i] > Components.interfaces.nsMsgSearchAttrib.OtherHeader && hdrsArray)
  1008.                 strings[i] = hdrsArray[j++];
  1009.               else
  1010.                 strings[i] = this.stringBundle.GetStringFromID(ids[i]);
  1011.             }
  1012.             return strings;
  1013.           ]]>
  1014.         </getter>
  1015.       </property>
  1016.       <property name="targets" readonly="true">
  1017.         <getter>
  1018.           <![CDATA[
  1019.             var forAttrs =  this.getAttribute("for");
  1020.             if (!forAttrs) return null;
  1021.             var targetIds = forAttrs.split(",");
  1022.             if (targetIds.length == 0) return null;
  1023.  
  1024.             var targets = new Array;
  1025.             var j=0;
  1026.             for (var i=0; i<targetIds.length;i++) {
  1027.               var target = document.getElementById(targetIds[i]);
  1028.               if (target) targets[j++] = target;
  1029.             }
  1030.             return targets;
  1031.           ]]>
  1032.         </getter>
  1033.       </property>
  1034.  
  1035.       <property name="optargets" readonly="true">
  1036.         <getter>
  1037.           <![CDATA[
  1038.             var forAttrs =  this.getAttribute("opfor");
  1039.             if (!forAttrs) return null;
  1040.             var optargetIds = forAttrs.split(",");
  1041.             if (optargetIds.length == 0) return null;
  1042.  
  1043.             var optargets = new Array;
  1044.             var j=0;
  1045.             for (var i=0; i<optargetIds.length;i++) {
  1046.               var optarget = document.getElementById(optargetIds[i]);
  1047.               if (optarget) optargets[j++] = optarget;
  1048.             }
  1049.             return optargets;
  1050.           ]]>
  1051.         </getter>
  1052.       </property>
  1053.  
  1054.       <!-- value forwards to the internal menulist's "value" attribute -->
  1055.       <property name="value" onget="return document.getAnonymousNodes(this)[0].selectedItem.getAttribute('value');">
  1056.         <setter>
  1057.           <![CDATA[
  1058.             var menulist = document.getAnonymousNodes(this)[0];
  1059.             var dataItems = menulist.getElementsByAttribute("value", val);
  1060.             if (dataItems.item(0))
  1061.                 menulist.selectedItem = dataItems[0];
  1062.  
  1063.             // now notify targets of new parent's value
  1064.             var targets = this.targets;
  1065.             if (targets) {
  1066.               for (var i=0; i < targets.length; i++) {
  1067.                 targets[i].parentValue = val;
  1068.               }
  1069.             }
  1070.  
  1071.             // now notify optargets of new op parent's value
  1072.             var optargets = this.optargets;
  1073.             if (optargets) {
  1074.               for (i=0; i < optargets.length; i++) {
  1075.                 optargets[i].opParentValue = val;
  1076.               }
  1077.             }
  1078.  
  1079.             return val;
  1080.           ]]>
  1081.         </setter>
  1082.       </property>
  1083.       <!-- label forwards to the internal menulist's "label" attribute -->
  1084.       <property name="label" onget="return document.getAnonymousNodes(this)[0].selectedItem.getAttribute('label');">
  1085.       </property>        
  1086.       <method name="refreshList">
  1087.         <body>
  1088.           <![CDATA[
  1089.             var menuItemIds = this.valueIds;
  1090.             var menuItemStrings = this.valueStrings;
  1091.  
  1092.             var menulist = document.getAnonymousNodes(this)[0];
  1093.             var popup = menulist.firstChild;
  1094.  
  1095.             // save our old "value" so we can restore it later
  1096.             var oldData = menulist.value;
  1097.  
  1098.             // remove the old popup children
  1099.             while (popup.hasChildNodes())
  1100.               popup.removeChild(popup.lastChild);
  1101.  
  1102.             var newSelection;
  1103.             var customizePos=-1;
  1104.             for (var i=0; i<menuItemIds.length; i++) 
  1105.             {
  1106.               // create the menuitem
  1107.               if (Components.interfaces.nsMsgSearchAttrib.OtherHeader == menuItemIds[i].toString())
  1108.                 customizePos = i;
  1109.               else
  1110.               {
  1111.                 var menuitem = document.createElement("menuitem");
  1112.                 menuitem.setAttribute("label", menuItemStrings[i]);
  1113.                 menuitem.setAttribute("value", menuItemIds[i]);
  1114.                 popup.appendChild(menuitem);
  1115.                 // try to restore the selection
  1116.                 if (!newSelection || oldData == menuItemIds[i].toString())
  1117.                   newSelection = menuitem;
  1118.               }
  1119.             }
  1120.             if (customizePos != -1)
  1121.             {
  1122.               var separator = document.createElement("menuseparator");
  1123.               popup.appendChild(separator);
  1124.               menuitem = document.createElement("menuitem");
  1125.               menuitem.setAttribute("label", menuItemStrings[customizePos]);
  1126.               menuitem.setAttribute("value", menuItemIds[customizePos]);
  1127.               popup.appendChild(menuitem);
  1128.             }
  1129.             // now restore the selection
  1130.             menulist.selectedItem = newSelection;
  1131.              
  1132.           ]]>
  1133.         </body>
  1134.       </method>
  1135.       <method name="onSelect">
  1136.         <parameter name="event"/>
  1137.         <body>
  1138.           <![CDATA[
  1139.             var menulist = document.getAnonymousNodes(this)[0];
  1140.             // notify targets
  1141.             var targets = this.targets;
  1142.             if (targets) {
  1143.               for (var i=0; i < targets.length; i++) {
  1144.                 targets[i].parentValue = menulist.value;
  1145.               }
  1146.             }
  1147.  
  1148.             var optargets = this.optargets;
  1149.             if (optargets) {
  1150.               for (i=0; i < optargets.length; i++) { 
  1151.                 optargets[i].opParentValue = menulist.value;
  1152.               }
  1153.             }
  1154.           ]]>
  1155.         </body>
  1156.       </method>
  1157.     </implementation>
  1158.   </binding>
  1159.  
  1160.   <!-- searchattribute - Subject, Sender, To, CC, etc. -->
  1161.   <binding id="searchattribute" name="searchAttribute"
  1162.            extends="chrome://messenger/content/mailWidgets.xml#search-menulist-abstract">
  1163.     <implementation>
  1164.       <field name="stringBundle">
  1165.           <![CDATA[
  1166.            srGetStrBundle("chrome://messenger/locale/search-attributes.properties");
  1167.           ]]>
  1168.       </field>
  1169.       <property name="valueIds" readonly="true">
  1170.         <getter>
  1171.           <![CDATA[
  1172.             var length = new Object;
  1173.             return this.validityTable.getAvailableAttributes(length);
  1174.           ]]>
  1175.         </getter>
  1176.       </property>
  1177.       <constructor>
  1178.       <![CDATA[
  1179.         initializeTermFromId(this.id);
  1180.       ]]>
  1181.       </constructor>
  1182.     </implementation>
  1183.   </binding>
  1184.  
  1185.   <!-- searchoperator - Contains, Is Less than, etc -->
  1186.   <binding id="searchoperator" name="searchOperator"
  1187.            extends="chrome://messenger/content/mailWidgets.xml#search-menulist-abstract">
  1188.     <implementation>
  1189.       <field name="searchAttribute">Components.interfaces.nsMsgSearchAttrib.Default</field>
  1190.       <field name="stringBundle">
  1191.           <![CDATA[
  1192.             srGetStrBundle("chrome://messenger/locale/search-operators.properties");
  1193.           ]]>
  1194.       </field>
  1195.       <property name="valueIds" readonly="true">
  1196.         <getter>
  1197.           <![CDATA[
  1198.             var length = new Object;
  1199.             return this.validityTable.getAvailableOperators(this.searchAttribute,length);
  1200.           ]]>
  1201.         </getter>
  1202.       </property>
  1203.       <property name="parentValue">
  1204.         <setter>
  1205.           <![CDATA[
  1206.             if (this.searchAttribute == val && val != Components.interfaces.nsMsgSearchAttrib.OtherHeader) return val;
  1207.             this.searchAttribute = val;
  1208.             this.refreshList();
  1209.             if (val == Components.interfaces.nsMsgSearchAttrib.OtherHeader)
  1210.             {
  1211.               window.openDialog('chrome://messenger/content/CustomHeaders.xul', "", 'modal,centerscreen,resizable,titlebar,chrome', null);
  1212.               setTimeout(UpdateAfterCustomHeaderChange, 0); // XXX bug 212625
  1213.             }
  1214.             return val;
  1215.           ]]>
  1216.         </setter>
  1217.         <getter>
  1218.           <![CDATA[
  1219.             return this.searchAttribute;
  1220.           ]]>
  1221.         </getter>
  1222.       </property>
  1223.     </implementation>
  1224.   </binding>
  1225.  
  1226.   <!-- searchvalue - a widget which dynamically changes its user interface
  1227.        depending on what type of data it's supposed to be showing
  1228.        currently handles arbitrary text entry, and menulists for 
  1229.        priority, status, junk status, hasAttachment status, and addressbook
  1230.   -->
  1231.   <binding id="searchvalue" name="searchValue">
  1232.     <content>
  1233.       <xul:textbox flex="1" class="search-value-textbox"/>
  1234.       <xul:menulist flex="1" class="search-value-menulist">
  1235.         <xul:menupopup class="search-value-popup">
  1236.           <xul:menuitem value="2" stringTag="priorityLowest" class="search-value-menuitem"/>
  1237.           <xul:menuitem value="3" stringTag="priorityLow" class="search-value-menuitem"/>
  1238.           <xul:menuitem value="4" stringTag="priorityNormal" class="search-value-menuitem"/>
  1239.           <xul:menuitem value="5" stringTag="priorityHigh" class="search-value-menuitem"/>
  1240.           <xul:menuitem value="6" stringTag="priorityHighest" class="search-value-menuitem"/>
  1241.         </xul:menupopup>
  1242.       </xul:menulist>
  1243.       <xul:menulist flex="1" class="search-value-menulist">
  1244.         <xul:menupopup class="search-value-popup">
  1245.           <xul:menuitem value="2" stringTag="replied" class="search-value-menuitem"/>
  1246.           <xul:menuitem value="1" stringTag="read" class="search-value-menuitem"/>
  1247.           <xul:menuitem value="65536" stringTag="new" class="search-value-menuitem"/>
  1248.           <xul:menuitem value="4096" stringTag="forwarded" class="search-value-menuitem"/>
  1249.           <xul:menuitem value="4" stringTag="flagged" class="search-value-menuitem"/>
  1250.         </xul:menupopup>
  1251.       </xul:menulist>
  1252.       <xul:textbox flex="1" class="search-value-textbox"/>
  1253.       <xul:menulist flex="1" class="search-value-menulist">
  1254.         <xul:menupopup class="search-value-popup" ref="moz-abdirectory://" 
  1255.                  datasources="rdf:addressdirectory"
  1256.                  sortActive="true"
  1257.                  sortDirection="ascending"
  1258.                  sortResource="http://home.netscape.com/NC-rdf#DirTreeNameSort">
  1259.           <xul:template>
  1260.             <xul:rule nc:IsRemote="true"/>
  1261.             <xul:rule nc:IsMailList="false">
  1262.               <xul:menuitem uri="..."
  1263.                     label="rdf:http://home.netscape.com/NC-rdf#DirName"
  1264.                     value="rdf:http://home.netscape.com/NC-rdf#DirUri"/>
  1265.             </xul:rule>
  1266.           </xul:template>
  1267.         </xul:menupopup>
  1268.       </xul:menulist>
  1269.       <xul:menulist flex="1" class="search-value-menulist">
  1270.         <xul:menupopup class="search-value-popup">
  1271.           <xul:menuitem value="0" class="search-value-menuitem"/>
  1272.           <xul:menuitem value="1" class="search-value-menuitem"/>
  1273.           <xul:menuitem value="2" class="search-value-menuitem"/>
  1274.           <xul:menuitem value="3" class="search-value-menuitem"/>
  1275.           <xul:menuitem value="4" class="search-value-menuitem"/>
  1276.           <xul:menuitem value="5" class="search-value-menuitem"/>
  1277.         </xul:menupopup>
  1278.       </xul:menulist>
  1279.       <xul:menulist flex="1" class="search-value-menulist">
  1280.         <xul:menupopup class="search-value-popup">
  1281.           <xul:menuitem value="2" stringTag="junk" class="search-value-menuitem"/>
  1282.         </xul:menupopup>
  1283.       </xul:menulist>
  1284.       <xul:menulist flex="1" class="search-value-menulist">
  1285.         <xul:menupopup class="search-value-popup">
  1286.           <xul:menuitem value="0" stringTag="hasAttachments" class="search-value-menuitem"/>
  1287.         </xul:menupopup>
  1288.       </xul:menulist>
  1289.     </content>
  1290.     <implementation>
  1291.       <field name="internalOperator">null</field>
  1292.       <field name="internalAttribute">null</field>
  1293.       <field name="internalValue">null</field>
  1294.       
  1295.       <property name="opParentValue" onget="return this.internalOperator;">
  1296.         <setter>
  1297.           <![CDATA[
  1298.             // noop if we're not changing it
  1299.             if (this.internalOperator == val) return val;
  1300.             
  1301.             // if it's not sender, we don't care
  1302.             if (this.searchAttribute != Components.interfaces.nsMsgSearchAttrib.Sender) {
  1303.               this.internalOperator = val;
  1304.               return val;
  1305.             }
  1306.  
  1307.             var children = document.getAnonymousNodes(this);
  1308.             if (val == Components.interfaces.nsMsgSearchOp.IsntInAB ||
  1309.                 val == Components.interfaces.nsMsgSearchOp.IsInAB) {
  1310.               // if the old internalOperator was 
  1311.               // IsntInAB or IsInAB, and the new internalOperator is
  1312.               // IsntInAB or IsInAB, noop because the search value
  1313.               // was an ab type, and it still is.
  1314.               // otherwise, switch to the ab picker and select the PAB
  1315.               if (this.internalOperator != Components.interfaces.nsMsgSearchOp.IsntInAB &&
  1316.                   this.internalOperator != Components.interfaces.nsMsgSearchOp.IsInAB) {
  1317.                 var abs = children[4].getElementsByAttribute("value", "moz-abmdbdirectory://abook.mab");
  1318.                 if (abs.item(0)) 
  1319.                   children[4].selectedItem = abs[0];   
  1320.                 this.setAttribute("selectedIndex", "4");
  1321.               }
  1322.             }
  1323.             else {
  1324.               // if the old internalOperator wasn't
  1325.               // IsntInAB or IsInAB, and the new internalOperator isn't
  1326.               // IsntInAB or IsInAB, noop because the search value
  1327.               // wasn't an ab type, and it still isn't.
  1328.               // otherwise, switch to the textbox and clear it
  1329.               if (this.internalOperator == Components.interfaces.nsMsgSearchOp.IsntInAB ||
  1330.                   this.internalOperator == Components.interfaces.nsMsgSearchOp.IsInAB) {
  1331.                 children[0].value = "";
  1332.                 this.setAttribute("selectedIndex", "0");
  1333.               }
  1334.             }
  1335.  
  1336.             this.internalOperator = val;
  1337.             return val;
  1338.           ]]>
  1339.         </setter>
  1340.       </property>
  1341.       <!-- parentValue forwards to the attribute -->
  1342.       <property name="parentValue" onset="return this.searchAttribute=val;"
  1343.                                    onget="return this.searchAttribute;"/>
  1344.       <property name="searchAttribute" onget="return this.internalAttribute;">
  1345.         <setter>
  1346.           <![CDATA[
  1347.             // noop if we're not changing it
  1348.             if (this.internalAttribute == val) return val;
  1349.             this.internalAttribute = val;
  1350.  
  1351.             // if the searchAttribute changing, null out the internalOperator
  1352.             this.internalOperator = null; 
  1353.  
  1354.             // we inherit from a deck, so just use it's index attribute
  1355.             // to hide/show widgets
  1356.             if (val == Components.interfaces.nsMsgSearchAttrib.Priority)
  1357.               this.setAttribute("selectedIndex", "1");
  1358.             else if (val == Components.interfaces.nsMsgSearchAttrib.MsgStatus)
  1359.               this.setAttribute("selectedIndex", "2");
  1360.             else if (val == Components.interfaces.nsMsgSearchAttrib.Date)
  1361.               this.setAttribute("selectedIndex", "3");
  1362.             else if (val == Components.interfaces.nsMsgSearchAttrib.Sender) {
  1363.               // since the internalOperator is null
  1364.               // this is the same as the initial state
  1365.               // the initial state for Sender isn't an ab type search
  1366.               // it's a text search, so show the textbox
  1367.               this.setAttribute("selectedIndex", "0");             
  1368.             }
  1369.             else if (val == Components.interfaces.nsMsgSearchAttrib.Label)
  1370.             {
  1371.               var children = document.getAnonymousNodes(this);
  1372.               var abs = children[5].getElementsByAttribute("value", "1");
  1373.               if (abs.item(0)) 
  1374.                 children[5].selectedItem = abs[0];                 
  1375.               this.setAttribute("selectedIndex", "5");
  1376.             }
  1377.             else if (val == Components.interfaces.nsMsgSearchAttrib.JunkStatus) {
  1378.               this.setAttribute("selectedIndex", "6");
  1379.             }
  1380.             else if (val == Components.interfaces.nsMsgSearchAttrib.HasAttachmentStatus) {
  1381.               this.setAttribute("selectedIndex", "7");
  1382.             }
  1383.             else {
  1384.               // a normal text field
  1385.               this.setAttribute("selectedIndex", "0");
  1386.             }
  1387.             return val;
  1388.           ]]>
  1389.         </setter>
  1390.       </property>
  1391.       <property name="value" onget="return this.internalValue;">
  1392.         <setter>
  1393.           <![CDATA[
  1394.           // val is a nsIMsgSearchValue object
  1395.           this.internalValue = val;
  1396.           var attrib = val.attrib;
  1397.           var nsMsgSearchAttrib = Components.interfaces.nsMsgSearchAttrib;
  1398.           var children = document.getAnonymousNodes(this);
  1399.           this.searchAttribute = attrib;
  1400.           if (attrib == nsMsgSearchAttrib.Priority) {
  1401.             var matchingPriority =
  1402.               children[1].getElementsByAttribute("value", val.priority);
  1403.             if (matchingPriority.item(0))
  1404.               children[1].selectedItem = matchingPriority[0];
  1405.           }
  1406.           else if (attrib == nsMsgSearchAttrib.MsgStatus) {
  1407.             var matchingStatus =
  1408.               children[2].getElementsByAttribute("value", val.status);
  1409.             if (matchingStatus.item(0)) 
  1410.               children[2].selectedItem = matchingStatus[0];
  1411.           }
  1412.           else if (attrib == nsMsgSearchAttrib.AgeInDays)
  1413.             children[0].value = val.age;
  1414.           else if (attrib == nsMsgSearchAttrib.Date)
  1415.             children[3].value = convertPRTimeToString(val.date);
  1416.           else if (attrib == nsMsgSearchAttrib.Sender)
  1417.           { 
  1418.             if (this.internalOperator == Components.interfaces.nsMsgSearchOp.IsntInAB ||
  1419.                 this.internalOperator == Components.interfaces.nsMsgSearchOp.IsInAB) {
  1420.               var abs = children[4].getElementsByAttribute("value", val.str);
  1421.               if (abs.item(0)) 
  1422.                 children[4].selectedItem = abs[0];    
  1423.             }
  1424.             else
  1425.               children[0].value = val.str;
  1426.           }
  1427.           else if (attrib == nsMsgSearchAttrib.Label)
  1428.           {
  1429.             var labelVal = children[5].getElementsByAttribute("value", val.label);
  1430.             if (labelVal.item(0))
  1431.               children[5].selectedItem = labelVal[0];
  1432.           }
  1433.           else if (attrib == nsMsgSearchAttrib.JunkStatus) {
  1434.             var junkStatus =
  1435.               children[6].getElementsByAttribute("value", val.junkStatus);
  1436.             if (junkStatus.item(0)) 
  1437.               children[6].selectedItem = junkStatus[0];
  1438.           }
  1439.           else if (attrib == nsMsgSearchAttrib.HasAttachmentStatus) {
  1440.             var hasAttachmentStatus =
  1441.               children[7].getElementsByAttribute("value", val.hasAttachmentStatus);
  1442.             if (hasAttachmentStatus.item(0)) 
  1443.               children[7].selectedItem = hasAttachmentStatus[0];
  1444.           }
  1445.           else if (attrib == nsMsgSearchAttrib.Size) {
  1446.             children[0].value = val.size;
  1447.           }
  1448.           else 
  1449.             children[0].value = val.str;
  1450.           return val;
  1451.           ]]>
  1452.         </setter>
  1453.       </property>
  1454.       <method name="save">
  1455.         <body>
  1456.           <![CDATA[
  1457.             var searchValue = this.value;
  1458.             var searchAttribute = this.searchAttribute;
  1459.             var nsMsgSearchAttrib = Components.interfaces.nsMsgSearchAttrib;
  1460.             var children = document.getAnonymousNodes(this);
  1461.  
  1462.             searchValue.attrib = searchAttribute;
  1463.             if (searchAttribute == nsMsgSearchAttrib.Priority) {
  1464.                searchValue.priority = children[1].selectedItem.value;
  1465.             }
  1466.             else if (searchAttribute == nsMsgSearchAttrib.MsgStatus)
  1467.                searchValue.status = children[2].value;
  1468.             else if (searchAttribute == nsMsgSearchAttrib.AgeInDays)
  1469.                searchValue.age = children[0].value;
  1470.             else if (searchAttribute == nsMsgSearchAttrib.Date)
  1471.                searchValue.date = convertStringToPRTime(children[3].value);
  1472.             else if (searchAttribute == nsMsgSearchAttrib.Sender) {
  1473.               if (this.internalOperator == Components.interfaces.nsMsgSearchOp.IsntInAB ||
  1474.                   this.internalOperator == Components.interfaces.nsMsgSearchOp.IsInAB)
  1475.                 searchValue.str = children[4].selectedItem.value;
  1476.               else
  1477.                 searchValue.str = children[0].value;
  1478.             }
  1479.             else if (searchAttribute == nsMsgSearchAttrib.Label)
  1480.               searchValue.label = children[5].selectedItem.value;
  1481.             else if (searchAttribute == nsMsgSearchAttrib.JunkStatus)
  1482.                searchValue.junkStatus = children[6].value;
  1483.             else if (searchAttribute == nsMsgSearchAttrib.Size)
  1484.                searchValue.size = children[0].value;
  1485.             else if (searchAttribute == nsMsgSearchAttrib.HasAttachmentStatus)
  1486.                searchValue.status = 0x10000000;  // 0x10000000 is MSG_FLAG_ATTACHMENT;
  1487.             else
  1488.                searchValue.str = children[0].value;
  1489.           ]]>
  1490.         </body>
  1491.       </method>
  1492.       <method name="saveTo">
  1493.         <parameter name="searchValue"/>
  1494.         <body>
  1495.           <![CDATA[
  1496.             this.internalValue = searchValue;
  1497.             this.save();
  1498.           ]]>
  1499.         </body>
  1500.       </method>
  1501.       <method name="fillStringsForChildren">
  1502.         <parameter name="parentNode"/>
  1503.         <parameter name="bundle"/>
  1504.         <body>
  1505.           <![CDATA[
  1506.             var children = parentNode.childNodes;
  1507.             var len=children.length;
  1508.             for (var i=0; i<len; i++) {
  1509.               var node = children[i];              
  1510.               var stringTag = node.getAttribute("stringTag");
  1511.               if (stringTag) {
  1512.                 var attr = (node.tagName == "label") ? "value" : "label";
  1513.                 node.setAttribute(attr, bundle.GetStringFromName(stringTag));
  1514.               }
  1515.             }
  1516.           ]]>
  1517.         </body>
  1518.       </method>
  1519.       <method name="initialize">
  1520.         <parameter name="menulist"/>
  1521.         <parameter name="bundle"/>
  1522.         <body>
  1523.           <![CDATA[
  1524.             this.fillStringsForChildren(menulist.firstChild, bundle);
  1525.           ]]>
  1526.         </body>
  1527.       </method>
  1528.       <constructor>
  1529.       <![CDATA[
  1530.         // initialize strings
  1531.         var bundle = srGetStrBundle("chrome://messenger/locale/messenger.properties");
  1532.  
  1533.         // intialize the priority picker
  1534.         this.initialize(document.getAnonymousNodes(this)[1], bundle);
  1535.        
  1536.         // initialize the status picker
  1537.         this.initialize(document.getAnonymousNodes(this)[2], bundle);
  1538.  
  1539.         // initialize the date picker
  1540.         var datePicker = document.getAnonymousNodes(this)[3];
  1541.         var searchAttribute = this.searchAttribute;
  1542.         var nsMsgSearchAttrib = Components.interfaces.nsMsgSearchAttrib;
  1543.         var time;
  1544.         if (searchAttribute == nsMsgSearchAttrib.Date)
  1545.          time = datePicker.value;
  1546.         else
  1547.          time = new Date();
  1548.         // do .value instead of .setAttribute("value", xxx);
  1549.         // to work around for bug #179412
  1550.         // (caused by bug #157210)
  1551.         //
  1552.         // the searchvalue widget has two textboxes
  1553.         // one for text, one as a placeholder for a date / calendar widget
  1554.         datePicker.value = convertDateToString(time);
  1555.  
  1556.         // initialize the address book picker
  1557.         this.initialize(document.getAnonymousNodes(this)[4], bundle);
  1558.  
  1559.         // initialize the label picker....
  1560.         var labelStrings = GetLabelStrings();
  1561.         var children = document.getAnonymousNodes(this)[5].firstChild.childNodes;
  1562.         // set the label string on each label element...
  1563.         for (var index = 0; index < 6; index++)
  1564.           children[index].setAttribute('label', labelStrings[index]);
  1565.  
  1566.         // initialize the junk status picker
  1567.         this.initialize(document.getAnonymousNodes(this)[6], bundle);
  1568.  
  1569.         // initialize the has attachment status picker
  1570.         this.initialize(document.getAnonymousNodes(this)[7], bundle);
  1571.       ]]>
  1572.       </constructor>
  1573.     </implementation>
  1574.     <handlers>
  1575.     <handler event="keypress" keycode="VK_RETURN" action="onEnterInSearchTerm();"/>
  1576.     </handlers>
  1577.   </binding>
  1578.   <binding id="searchterm" name="searchTerm" extends="xul:box">
  1579.     <implementation>
  1580.       <field name="internalSearchTerm">null</field>
  1581.       <field name="internalBooleanAnd">null</field>
  1582.       <!-- the actual nsIMsgSearchTerm object -->
  1583.       <property name="searchTerm" onget="return this.internalSearchTerm">
  1584.         <setter>
  1585.           <![CDATA[
  1586.             this.internalSearchTerm = val;
  1587.  
  1588.             var term = val;
  1589.             // val is a nsIMsgSearchTerm
  1590.             var searchAttribute=this.searchattribute;
  1591.             var searchOperator=this.searchoperator;
  1592.             var searchValue=this.searchvalue;
  1593.  
  1594.             // now reflect all attributes of the searchterm into the widgets
  1595.             if (searchAttribute) searchAttribute.value = term.attrib;
  1596.             if (searchOperator) searchOperator.value = val.op;
  1597.             if (searchValue) searchValue.value = term.value;
  1598.  
  1599.             this.booleanAnd = val.booleanAnd;
  1600.           ]]>
  1601.         </setter>
  1602.       </property>
  1603.  
  1604.       <property name="searchScope">
  1605.         <getter>
  1606.           <![CDATA[
  1607.              var searchAttribute = this.searchattribute;
  1608.              if (searchAttribute)
  1609.                return searchAttribute.searchScope;
  1610.              return undefined;
  1611.            ]]>
  1612.         </getter>
  1613.         <setter>
  1614.           <![CDATA[
  1615.             var searchAttribute = this.searchattribute;
  1616.             if (searchAttribute) searchAttribute.searchScope=val;
  1617.            ]]>
  1618.         </setter>
  1619.       </property>
  1620.       <!-- the three tags that make up a term - to use, set the
  1621.            attribute in the XUL to the ID of the term.
  1622.         -->
  1623.       <property name="searchattribute" 
  1624.                 onget="return document.getElementById(this.getAttribute('searchattribute'));"
  1625.                 onset="this.setAttribute('searchattribute',val.id)"/>
  1626.  
  1627.       <property name="searchoperator" 
  1628.                 onget="return document.getElementById(this.getAttribute('searchoperator'));"
  1629.                 onset="this.setAttribute('searchoperator',val.id)"/>
  1630.  
  1631.       <property name="searchvalue" 
  1632.                 onget="return document.getElementById(this.getAttribute('searchvalue'));"
  1633.                 onset="this.setAttribute('searchvalue',val.id)"/>
  1634.       <field name="booleanNodes">
  1635.         <![CDATA[
  1636.           null;
  1637.         ]]>
  1638.       </field>
  1639.       <field name="stringBundle">
  1640.           <![CDATA[
  1641.              srGetStrBundle("chrome://messenger/locale/search.properties");
  1642.           ]]>
  1643.       </field>
  1644.       <property name="booleanAnd" onget="return this.internalBooleanAnd">
  1645.         <setter>
  1646.           <![CDATA[
  1647.             // whenever you set this, all nodes in booleanNodes
  1648.             // are updated to reflect the string
  1649.  
  1650.             if (this.internalBooleanAnd == val) return;
  1651.             this.internalBooleanAnd = val;
  1652.  
  1653.             var booleanNodes = this.booleanNodes;
  1654.             if (!booleanNodes) return;
  1655.  
  1656.             var stringBundle = this.stringBundle;
  1657.             var andString = val ? "And" : "Or";
  1658.             for (var i=0; i<booleanNodes.length; i++) {
  1659.               try {              
  1660.                 var staticString =
  1661.                     stringBundle.GetStringFromName("search" + andString + i);
  1662.                 if (staticString && staticString.length>0)
  1663.                     booleanNodes[i].setAttribute("value", staticString);
  1664.               } catch (ex) { /* no error, means string not found */}
  1665.             }
  1666.           ]]>
  1667.         </setter>
  1668.       </property>
  1669.       <method name="save">
  1670.         <body>
  1671.           <![CDATA[
  1672.             var searchTerm = this.searchTerm;
  1673.             searchTerm.attrib = this.searchattribute.value;
  1674.             if (this.searchAttribute > nsMsgSearchAttrib.OtherHeader && this.searchAttribute < nsMsgSearchAttrib.kNumMsgSearchAttributes) 
  1675.               searchTerm.arbitraryHeader = this.searchattribute.label;
  1676.             searchTerm.op = this.searchoperator.value;
  1677.             if (this.searchvalue.value)
  1678.               this.searchvalue.save();
  1679.             else
  1680.               this.searchvalue.saveTo(searchTerm.value);
  1681.             searchTerm.value = this.searchvalue.value;
  1682.             searchTerm.booleanAnd = this.booleanAnd;
  1683.           ]]>
  1684.         </body>
  1685.       </method>
  1686.       <!-- if you have a search term element with no search term -->
  1687.       <method name="saveTo">
  1688.         <parameter name="searchTerm"/>
  1689.         <body>
  1690.           <![CDATA[
  1691.             this.internalSearchTerm = searchTerm;
  1692.             this.save();
  1693.           ]]>
  1694.         </body>
  1695.       </method>
  1696.     </implementation>
  1697.   </binding>
  1698.  
  1699.   <!-- Folder picker helper widgets -->
  1700.   <binding id="popup-base" extends="chrome://global/content/bindings/popup.xml#popup">
  1701.     <implementation>
  1702.       <field name="tree" readonly="true">
  1703.         document.getAnonymousNodes(this)[0];
  1704.       </field>
  1705.       <method name="updateHover">
  1706.         <parameter name="event"/>
  1707.         <body>
  1708.           <![CDATA[
  1709.             var box = this.tree.boxObject;
  1710.             if (event.originalTarget == box.treeBody) {
  1711.               // XXXbz We really want client*, but event.client* is bogus inside a popup!
  1712.               var eventX = event.screenX - document.documentElement.boxObject.screenX;
  1713.               var eventY = event.screenY - document.documentElement.boxObject.screenY;
  1714.               box.view.selection.select(box.getRowAt(eventX, eventY));
  1715.             }
  1716.           ]]>
  1717.         </body>
  1718.       </method>
  1719.       <method name="fire">
  1720.         <body>
  1721.           <![CDATA[
  1722.             this.hidePopup();
  1723.             if (this.tree.currentIndex >= 0) {
  1724.               this.setAttribute("uri", this.tree.builderView.getResourceAtIndex(this.tree.currentIndex).Value);
  1725.               this.doCommand();
  1726.             }
  1727.           ]]>
  1728.         </body>
  1729.       </method>
  1730.       <method name="onBlurMenuList">
  1731.         <parameter name="event"/>
  1732.         <body>
  1733.           <![CDATA[
  1734.             this.boxObject.QueryInterface(Components.interfaces.nsIMenuBoxObject).openMenu(false);
  1735.           ]]>
  1736.         </body>
  1737.       </method>
  1738.       <field name="onKeyDownMenuList" readonly="true">
  1739.         <![CDATA[
  1740.           ({
  1741.             parentNode: this.parentNode,
  1742.             handleEvent: function handleEvent(event) {
  1743.               if (this.parentNode.hasAttribute("open"))
  1744.                 event.stopPropagation();
  1745.             }
  1746.           })
  1747.         ]]>
  1748.       </field>
  1749.       <field name="onKeyPressMenuList" readonly="true">
  1750.         <![CDATA[
  1751.           ({
  1752.             self: this,
  1753.             tree: this.tree,
  1754.             parentNode: this.parentNode,
  1755.             getLastVisibleRow: function getLastVisibleRow(box) {
  1756.               var f = box.getFirstVisibleRow();
  1757.               var p = box.getPageCount();
  1758.               var l = box.view.rowCount;
  1759.               return (l < f + p ? l : f + p) - 1;
  1760.             },
  1761.             handleEvent: function handleEvent(event) {
  1762.               if (event.altKey)
  1763.                 return;
  1764.               var index;
  1765.               var box = this.tree.treeBoxObject;
  1766.               if (this.parentNode.hasAttribute("open")) {
  1767.                 event.stopPropagation();
  1768.                 switch (event.keyCode) {
  1769.                   case event.DOM_VK_ESCAPE:
  1770.                     this.self.hidePopup();
  1771.                     return;
  1772.                   case event.DOM_VK_ENTER:
  1773.                   case event.DOM_VK_RETURN:
  1774.                     this.self.fire();
  1775.                     return;
  1776.                 }
  1777.                 index = this.tree.currentIndex;
  1778.               } else {
  1779.                 switch (event.keyCode) {
  1780.                   case event.DOM_VK_PAGE_UP:
  1781.                   case event.DOM_VK_PAGE_DOWN:
  1782.                     return;
  1783.                 }
  1784.                 index = this.self.setInitialSelection();
  1785.               }
  1786.               switch (event.keyCode) {
  1787.                 case event.DOM_VK_UP:
  1788.                   if (index <= 0)
  1789.                     return;
  1790.                   index--;
  1791.                   break;
  1792.                 case event.DOM_VK_DOWN:
  1793.                   index++;
  1794.                   if (index == box.view.rowCount)
  1795.                     return;
  1796.                   break;
  1797.                 case event.DOM_VK_PAGE_UP:
  1798.                   if (index == box.getFirstVisibleRow())
  1799.                     box.scrollByPages(-1);
  1800.                   index = box.getFirstVisibleRow();
  1801.                   break;
  1802.                 case event.DOM_VK_PAGE_DOWN:
  1803.                   if (index == this.getLastVisibleRow(box))
  1804.                     box.scrollByPages(1);
  1805.                   index = this.getLastVisibleRow(box);
  1806.                   break;
  1807.                 case event.DOM_VK_HOME:
  1808.                   index = 0;
  1809.                   break;
  1810.                 case event.DOM_VK_END:
  1811.                   index = box.view.rowCount - 1;
  1812.                   break;
  1813.                 default:
  1814.                   return;
  1815.               }
  1816.               box.view.selection.select(index);
  1817.               if (this.parentNode.hasAttribute("open"))
  1818.                 box.ensureRowIsVisible(index);
  1819.               else
  1820.                 this.self.fire();
  1821.             }
  1822.           })
  1823.         ]]>
  1824.       </field>
  1825.       <method name="setInitialSelection">
  1826.         <body>
  1827.           <![CDATA[
  1828.             var view = this.tree.view;
  1829.             view.selection.selectEventsSuppressed = true;
  1830.             for (var i = 0; i < view.rowCount; i++) {
  1831.               if (view.isContainer(i)) {
  1832.                 if (view.isContainerEmpty(i) == view.isContainerOpen(i))
  1833.                   view.toggleOpenState(i);
  1834.                 if (view.isContainerOpen(i)) {
  1835.                   if (i + 1 == view.rowCount ||
  1836.                       view.getLevel(i + 1) <= view.getLevel(i)) {
  1837.                     view.toggleOpenState(i);
  1838.                   }
  1839.                 }
  1840.               }
  1841.             }
  1842.             var index = -1;
  1843.             var uri = this.parentNode.getAttribute("uri");
  1844.             if (uri) {
  1845.               var RDF = Components.classes["@mozilla.org/rdf/rdf-service;1"].getService(Components.interfaces.nsIRDFService);
  1846.               index = view.getIndexOfResource(RDF.GetResource(uri));
  1847.             }
  1848.             view.selection.select(index);
  1849.             return index;
  1850.           ]]>
  1851.         </body>
  1852.       </method>
  1853.       <constructor>
  1854.         <![CDATA[
  1855.           this.parentNode.addEventListener("keypress", this.onKeyPressMenuList, true);
  1856.         ]]>
  1857.       </constructor>
  1858.       <destructor>
  1859.         <![CDATA[
  1860.           this.parentNode.removeEventListener("keypress", this.onKeyPressMenuList, true);
  1861.         ]]>
  1862.       </destructor>
  1863.     </implementation>
  1864.     <handlers>
  1865.       <handler event="mousemove" action="this.updateHover(event);"/>
  1866.       <handler event="click" action="this.updateHover(event);this.fire();"/>
  1867.       <handler event="popupshowing">
  1868.         <![CDATA[
  1869.           this.parentNode.addEventListener("blur", this.onBlurMenuList, false);
  1870.           window.top.document.addEventListener("keydown", this.onKeyDownMenuList, true);
  1871.           window.top.document.addEventListener("keypress", this.onKeyPressMenuList, true);
  1872.           var box = this.tree.treeBoxObject;
  1873.           box.focused = true;
  1874.           var index = this.setInitialSelection();
  1875.           var height = box.view.rowCount * box.rowHeight;
  1876.           height += this.boxObject.height - box.treeBody.boxObject.height;
  1877.           this.height = height;
  1878.           if (index >= 0)
  1879.             setTimeout(function() { box.ensureRowIsVisible(index); }, 0);
  1880.         ]]>
  1881.       </handler>
  1882.       <handler event="popuphiding">
  1883.         <![CDATA[
  1884.           this.parentNode.removeEventListener("blur", this.onBlurMenuList, false);
  1885.           window.top.document.removeEventListener("keydown", this.onKeyDownMenuList, true);
  1886.           window.top.document.removeEventListener("keypress", this.onKeyPressMenuList, true);
  1887.         ]]>
  1888.       </handler>
  1889.     </handlers>
  1890.   </binding>
  1891.  
  1892.   <binding id="folderTargetPopup" extends="chrome://messenger/content/mailWidgets.xml#popup-base">
  1893.     <xbl:content xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  1894.       <tree class="foldersTree" flex="1" datasources="rdf:msgaccountmanager rdf:mailnewsfolders" ref="msgaccounts:/" flags="dont-build-content" selstyle="primary" hidecolumnpicker="true">
  1895.         <treecols>
  1896.           <treecol flex="1" primary="true" sort="rdf:http://home.netscape.com/NC-rdf#FolderTreeName?sort=true" sortActive="true" sortDirection="ascending" crop="center" hideheader="true"/>
  1897.         </treecols>
  1898.         <treechildren class="foldersTreeChildren"/>
  1899.         <template>
  1900.           <rule nc:CanFileMessagesOnServer="true" nc:CanFileMessages="true" nc:CanSearchMessages="true">
  1901.             <treechildren>
  1902.               <treeitem uri="rdf:*">
  1903.                 <treerow sort="rdf:http://home.netscape.com/NC-rdf#FolderTreeName?sort=true">
  1904.                   <treecell label="rdf:http://home.netscape.com/NC-rdf#FolderTreeSimpleName"
  1905.                     properties="folderNameCol specialFolder-rdf:http://home.netscape.com/NC-rdf#SpecialFolder isServer-rdf:http://home.netscape.com/NC-rdf#IsServer isSecure-rdf:http://home.netscape.com/NC-rdf#IsSecure serverType-rdf:http://home.netscape.com/NC-rdf#ServerType noSelect-rdf:http://home.netscape.com/NC-rdf#NoSelect"/>
  1906.                 </treerow>
  1907.               </treeitem>
  1908.             </treechildren>
  1909.           </rule>
  1910.           <rule nc:CanFileMessagesOnServer="true" nc:CanFileMessages="false" nc:CanSearchMessages="true" nc:Virtual="false">
  1911.             <treechildren>
  1912.               <treeitem uri="rdf:*">
  1913.                 <treerow sort="rdf:http://home.netscape.com/NC-rdf#FolderTreeName?sort=true">
  1914.                   <treecell label="rdf:http://home.netscape.com/NC-rdf#FolderTreeSimpleName"
  1915.                     properties="folderNameCol specialFolder-rdf:http://home.netscape.com/NC-rdf#SpecialFolder isServer-rdf:http://home.netscape.com/NC-rdf#IsServer isSecure-rdf:http://home.netscape.com/NC-rdf#IsSecure serverType-rdf:http://home.netscape.com/NC-rdf#ServerType noSelect-rdf:http://home.netscape.com/NC-rdf#NoSelect"/>
  1916.                 </treerow>
  1917.               </treeitem>
  1918.             </treechildren>
  1919.           </rule>
  1920.           <rule nc:CanFileMessagesOnServer="true" nc:CanFileMessages="true" nc:Virtual="false">
  1921.             <treechildren>
  1922.               <treeitem uri="rdf:*">
  1923.                 <treerow sort="rdf:http://home.netscape.com/NC-rdf#FolderTreeName?sort=true">
  1924.                   <treecell label="rdf:http://home.netscape.com/NC-rdf#FolderTreeSimpleName"
  1925.                     properties="folderNameCol specialFolder-rdf:http://home.netscape.com/NC-rdf#SpecialFolder isServer-rdf:http://home.netscape.com/NC-rdf#IsServer isSecure-rdf:http://home.netscape.com/NC-rdf#IsSecure serverType-rdf:http://home.netscape.com/NC-rdf#ServerType noSelect-rdf:http://home.netscape.com/NC-rdf#NoSelect"/>
  1926.                 </treerow>
  1927.               </treeitem>
  1928.             </treechildren>
  1929.           </rule>
  1930.         </template>
  1931.       </tree>
  1932.     </xbl:content>
  1933.   </binding>
  1934.  
  1935.   <binding id="locationpopup" extends="chrome://messenger/content/mailWidgets.xml#popup-base">
  1936.     <xbl:content xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  1937.       <tree class="foldersTree" flex="1" datasources="rdf:null" flags="dont-build-content" selstyle="primary" hidecolumnpicker="true">
  1938.         <treecols>
  1939.           <treecol flex="1" primary="true" sort="rdf:http://home.netscape.com/NC-rdf#FolderTreeName?sort=true" sortActive="true" sortDirection="ascending" crop="center" hideheader="true"/>
  1940.         </treecols>
  1941.         <treechildren class="foldersTreeChildren"/>
  1942.         <template>
  1943.           <rule>
  1944.             <treechildren>
  1945.               <treeitem uri="rdf:*">
  1946.                 <treerow sort="rdf:http://home.netscape.com/NC-rdf#FolderTreeName?sort=true">
  1947.                   <treecell label="rdf:http://home.netscape.com/NC-rdf#FolderTreeName"
  1948.                     properties="folderNameCol specialFolder-rdf:http://home.netscape.com/NC-rdf#SpecialFolder biffState-rdf:http://home.netscape.com/NC-rdf#BiffState isServer-rdf:http://home.netscape.com/NC-rdf#IsServer newMessages-rdf:http://home.netscape.com/NC-rdf#NewMessages hasUnreadMessages-rdf:http://home.netscape.com/NC-rdf#HasUnreadMessages isSecure-rdf:http://home.netscape.com/NC-rdf#IsSecure serverType-rdf:http://home.netscape.com/NC-rdf#ServerType noSelect-rdf:http://home.netscape.com/NC-rdf#NoSelect"/>
  1949.                 </treerow>
  1950.               </treeitem>
  1951.             </treechildren>
  1952.           </rule>
  1953.         </template>
  1954.       </tree>
  1955.     </xbl:content>
  1956.   </binding>
  1957.  
  1958.   <binding id="searchpopup" extends="chrome://messenger/content/mailWidgets.xml#popup-base">
  1959.     <xbl:content xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  1960.       <tree class="foldersTree" flex="1" datasources="rdf:msgaccountmanager rdf:mailnewsfolders" ref="msgaccounts:/" flags="dont-build-content" selstyle="primary" hidecolumnpicker="true">
  1961.         <treecols>
  1962.           <treecol flex="1" primary="true" sort="rdf:http://home.netscape.com/NC-rdf#FolderTreeName?sort=true" sortActive="true" sortDirection="ascending" crop="center" hideheader="true"/>
  1963.         </treecols>
  1964.         <treechildren class="foldersTreeChildren"/>
  1965.         <template>
  1966.           <rule nc:CanSearchMessages="true" nc:Virtual="false">
  1967.             <treechildren>
  1968.               <treeitem uri="rdf:*">
  1969.                 <treerow sort="rdf:http://home.netscape.com/NC-rdf#FolderTreeName?sort=true">
  1970.                   <treecell label="rdf:http://home.netscape.com/NC-rdf#FolderTreeSimpleName"
  1971.                     properties="folderNameCol specialFolder-rdf:http://home.netscape.com/NC-rdf#SpecialFolder isServer-rdf:http://home.netscape.com/NC-rdf#IsServer isSecure-rdf:http://home.netscape.com/NC-rdf#IsSecure serverType-rdf:http://home.netscape.com/NC-rdf#ServerType noSelect-rdf:http://home.netscape.com/NC-rdf#NoSelect"/>
  1972.                 </treerow>
  1973.               </treeitem>
  1974.             </treechildren>
  1975.           </rule>
  1976.         </template>
  1977.       </tree>
  1978.     </xbl:content>
  1979.   </binding>
  1980.  
  1981. </bindings>
  1982.